// 以下注释展示了 RTCP 头部的二进制结构，共 4 字节（32 位）
//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P|    RC   |   PT          |             length            |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

use crate::rtsp::rtp::rtcp::errors::RtcpError;
use crate::rtsp::rtp::utils::{Marshal, Unmarshal};
use byteorder::BigEndian;
use bytes::BytesMut;
use bytesio::bytes_reader::BytesReader;
use bytesio::bytes_writer::BytesWriter;

// RTCP 头部结构体，用于表示 RTCP 数据包的头部信息
#[derive(Debug, Clone, Default)]
pub struct RtcpHeader {
    // 版本号
    pub version: u8,
    // 填充标志位
    pub padding_flag: u8,
    // 报告计数
    pub report_count: u8,
    // 负载类型
    pub payload_type: u8,
    // 数据包长度
    pub length: u16,
}

impl Unmarshal<&mut BytesReader, Result<Self, RtcpError>> for RtcpHeader {
    fn unmarshal(data: &mut BytesReader) -> Result<Self, RtcpError>
    where
        Self: Sized,
    {
        // 创建一个默认的 RtcpHeader 实例
        let mut rtcp_header = RtcpHeader::default();

        // 读取第一个字节
        let byte_1st: u8 = data.read_u8()?;
        // 从第一个字节中提取版本号，通过右移 6 位得到
        rtcp_header.version = byte_1st >> 6;
        // 从第一个字节中提取填充标志位，先右移 5 位，再与 0x01 进行按位进行与操作
        rtcp_header.padding_flag = (byte_1st >> 5) & 0x01;
        // 从第一个字节中提取报告计数，与 0x1F 进行按位进行与操作
        rtcp_header.report_count = byte_1st & 0x1F;
        // 读取第二个字节作为负载类型
        rtcp_header.payload_type = data.read_u8()?;
        // 以大端字节序读取接下来的 2 字节作为数据包长度
        rtcp_header.length = data.read_u16::<BigEndian>()?;

        Ok(rtcp_header)
    }
}

impl Marshal<Result<BytesMut, RtcpError>> for RtcpHeader {
    fn marshal(&self) -> Result<BytesMut, RtcpError> {
        // 创建一个默认的字节写入器
        let mut writer = BytesWriter::default();

        // 构造第一个字节，将版本号左移 6 位，填充标志位左移 5 位，然后与报告计数进行按位或操作
        let byte_1st: u8 = (self.version << 6) | (self.padding_flag << 5) | self.report_count;

        // 将构造好的第一个字节写入字节写入器
        writer.write_u8(byte_1st)?;
        // 将负载类型写入字节写入器
        writer.write_u8(self.payload_type)?;
        // 以大端字节序将数据包长度写入字节写入器
        writer.write_u16::<BigEndian>(self.length)?;

        // 提取字节写入器中的当前字节数据并返回
        Ok(writer.extract_current_bytes())
    }
}
